package com.sunday.common.mq.rabbit.study.base.e1_HelloWorld;

import com.rabbitmq.client.*;
import com.rabbitmq.client.impl.recovery.AutorecoveringChannel;
import com.sunday.common.mq.rabbit.study.base.ConnectionUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Slf4j
public class Recv {

    private final static String QUEUE_NAME = "hello";

    /**
     * 我们为什么不使用 try-with-resource 语句来自动关闭 通道和连接？
     * 通过这样做，我们将简单地制作程序 继续前进，关闭所有内容，然后退出！
     * 这会很尴尬，因为 我们希望这个过程在消费者倾听时保持活力 异步方式使消息到达。
     */
    public static void main(String[] argv) throws Exception {

        Connection connection = ConnectionUtil.factory().newConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        log.info(" [*] Waiting for messages. To exit press CTRL+C");

        /**
         * 当收到此消费者的<code><b>basic.deliver</b></code>时调用。
         * @param consumerTag <i>消费者标签</i>与消费者相关联
         * @param message 传递的信息
         * @throws 如果消费者在处理消息时遇到I/O错误
         */
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
            log.info("==========消费者one=========");
            log.info(" consumerTag : {} ", consumerTag);
            log.info(" envelope : {} ", delivery.getEnvelope());
            log.info(" properties : {} ", delivery.getProperties());
            log.info(" [x] Received '{}'", message);
        };

        /**
         * 创建一个非本地、非排他性的消费者
         * 一个服务器生成的消费者标签。
         * 只提供访问<code>basic.deliver</code> and
         *
         *  <代码>基本。取消</code> AMQP方法(这就足够了 在大多数情况下)。参见带有{@link Consumer}参数的方法 可以访问所有的应用程序回调。
         *
         * @param queue 队列的名称 如果服务器应该考虑消息，则@param autoAck为true
         * @param autoAck 如果服务器应该期望，则为False 明确致谢
         * @param deliverCallback 消息被发送时的回调函数
         * @param cancelCallback 当消费者被取消时回调
         * @返回由服务器生成的consumerTag
         * 如果遇到错误，@抛出IOException
         * @see com.rabbitmq.client.AMQP.Basic.Consume
         * @see com.rabbitmq.client.AMQP.Basic.ConsumeOk
         * @参见#basicAck
         * @see #basicConsume(String, boolean, String, boolean, boolean, Map, Consumer)
         */
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {
        });


        /**
         * 绑定消费者
         *
         * 启动一个非无地、非排他的消费者
         * 注册服务器生成的consumerTag。
         * @param queue 排队等待队列的名称 如果服务器应该考虑消息
         * @param autoAck true 承认一次交付;如果服务器应该期望 明确的确认
         * @param callback 回调一个面向消费者对象的接口返回由服务器生成的消费标签
         * @throws . io .如果遇到错误，IOException
         * @see AMQP.Basic.Consume
         * @see AMQP.Basic.ConsumeOk
         * @see basicconsumer（String、boolean、String、boolean、boolean、Map、消费者）
         *
         * String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;
         */
        channel.basicConsume(QUEUE_NAME, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag,
                                       Envelope envelope,
                                       AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                log.info("==========消费者two=========");
                //消费标签，消费者标签与消费者相关
                log.info(" consumerTag : {} ", consumerTag);
                log.info(" envelope : {} ", envelope);
                log.info(" properties : {} ", properties);
                String message = new String(body, "UTF-8");
                log.info(" [x] Received '{}'", message);
            }
        });

        /**
         * 其实上面的两个想法是相同的的操作
         * {@link AutorecoveringChannel#basicConsume(String, boolean, DeliverCallback, CancelCallback)}.
         * {@link AutorecoveringChannel#consumerFromDeliverCancelCallbacks(DeliverCallback, CancelCallback)}
         * 内部会构建一个 Consumer 对象，与上面操作等同
         */

    }
}
